/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Client.GUI.Controls;

import Client.LandInfo;
import Library.Game.PlayerColor;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.util.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import java.net.URL;
import javax.xml.parsers.*;
import org.w3c.dom.*;

/**
 * TODO: javadoc
 */
public class JWorldMapPanel extends JImagePanel
{
    protected int m_SelectionDotRadius = 15;
    protected List<LandInfo> m_Landen = new ArrayList<LandInfo>();
    protected LandInfo m_Selection1 = null;	// Selected land 1
    protected LandInfo m_Selection2 = null;	// Selected land 2
    protected Color m_Selection1Color = Color.green;
    protected Color m_Selection2Color = Color.red;
    
    public LandInfo getSelection1()
    {
	return m_Selection1;
    }
    
    public LandInfo getSelection2()
    {
	return m_Selection2;
    }
    
    public void setSelection1(LandInfo land)
    {
	m_Selection1 = land;
    }
    
    public void setSelection2(LandInfo land)
    {
	m_Selection2 = land;
    }
    
    public JWorldMapPanel(String mapname)
    {
        super("/resources/" + mapname + ".png");
        loadContent("/resources/" + mapname + ".xml");        
    }
    
    /**
    * Draws an arrow on the given Graphics context
    * @param g The Graphics context to draw on
    * @param x The x location of the "tail" of the arrow
    * @param y The y location of the "tail" of the arrow
    * @param xx The x location of the "head" of the arrow
    * @param yy The y location of the "head" of the arrow
    */
    protected void drawArrow(Graphics g, int x, int y, int xx, int yy)
    {
	float arrowWidth = 10.0f ;
	float theta = 0.423f ;
	int[] xPoints = new int[ 3 ] ;
	int[] yPoints = new int[ 3 ] ;
	float[] vecLine = new float[ 2 ] ;
	float[] vecLeft = new float[ 2 ] ;
	float fLength;
	float th;
	float ta;
	float baseX, baseY ;

	xPoints[ 0 ] = xx ;
	yPoints[ 0 ] = yy ;

	// build the line vector
	vecLine[ 0 ] = (float)xPoints[ 0 ] - x ;
	vecLine[ 1 ] = (float)yPoints[ 0 ] - y ;

	// build the arrow base vector - normal to the line
	vecLeft[ 0 ] = -vecLine[ 1 ] ;
	vecLeft[ 1 ] = vecLine[ 0 ] ;

	// setup length parameters
	fLength = (float)Math.sqrt( vecLine[0] * vecLine[0] + vecLine[1] * vecLine[1] ) ;
	th = arrowWidth / ( 2.0f * fLength ) ;
	ta = arrowWidth / ( 2.0f * ( (float)Math.tan( theta ) / 2.0f ) * fLength ) ;

	// find the base of the arrow
	baseX = ( (float)xPoints[ 0 ] - ta * vecLine[0]);
	baseY = ( (float)yPoints[ 0 ] - ta * vecLine[1]);

	// build the points on the sides of the arrow
	xPoints[ 1 ] = (int)( baseX + th * vecLeft[0] );
	yPoints[ 1 ] = (int)( baseY + th * vecLeft[1] );
	xPoints[ 2 ] = (int)( baseX - th * vecLeft[0] );
	yPoints[ 2 ] = (int)( baseY - th * vecLeft[1] );

	g.drawLine( x, y, (int)baseX, (int)baseY ) ;
	g.fillPolygon( xPoints, yPoints, 3 ) ;
    }
    
    @Override
    public void paint(Graphics g)
    {
        super.paint(g);
        Graphics gr = g;
        
	// Selections
        if (m_Selection2 != null)
        {
            gr.setColor(Color.RED);
	    drawArrow(g, m_Selection1.getX(), m_Selection1.getY(), m_Selection2.getX(), m_Selection2.getY());
        
            gr.setColor(m_Selection2Color);
            gr.fillOval(m_Selection2.getX() - m_SelectionDotRadius, m_Selection2.getY() - m_SelectionDotRadius, m_SelectionDotRadius * 2, m_SelectionDotRadius * 2);
	}
	
	if (m_Selection1 != null)
	{
            gr.setColor(m_Selection1Color);
            gr.fillOval(m_Selection1.getX() - m_SelectionDotRadius, m_Selection1.getY() - m_SelectionDotRadius, m_SelectionDotRadius * 2, m_SelectionDotRadius * 2);
        }        
        
	// Armies
        for (int x = 0; x < m_Landen.size(); x++)
        {
           try
           {
               LandInfo li = m_Landen.get(x);
               
               Font f = new Font("Verdana", 0, 16);
               g.setFont(f);
               FontMetrics m = g.getFontMetrics(f);
               int height = m.getHeight();
               int width = 0;
               String strAmount = new Integer(li.getAmountOfArmies()).toString();
               for (int t = 0; t < strAmount.length(); t++)
                    width += m.getWidths()[strAmount.charAt(t)] * 1.5;
               Color c = Color.BLACK;
               if (li.getOwner() == null)
                    g.setColor(PlayerColor.getColor(PlayerColor.NEURTALPLAYER));
               else
               {
                   int pc = li.getOwner().getColor();
                   c = PlayerColor.getColor(pc);
                    g.setColor(c);                    
               }
               
               g.fillRect(li.getX() - (width / 2), li.getY() - (height /2), width , height);  
               
               if(c.getRed() + c.getGreen() + c.getBlue() < 255)
               {
                    g.setColor(Color.BLACK);
               }
               else
               {
                   g.setColor(Color.WHITE);               
               }
               //g.drawRect(li.getX() + 1, li.getY() - (height - 7), width - 2, height - 6);
	       //IPlayer owner = li.getOwner();
               //Color c = PlayerColor.getInnerColor(owner == null ? PlayerColor.NEURTALPLAYER : owner.getColor());
               //g.setColor(c);
               g.drawRect(li.getX() - (width / 2), li.getY() - (height /2), width , height);
               g.drawString(strAmount, li.getX() - (width / 3), li.getY() + (height /4));
           }
           catch (Exception ex)
           {
               ex.printStackTrace();
           }
        }        
    }
    
    public void loadContent(String resourceFile)
    {
         try
         {
              URL xmlUrl = Image.class.getResource(resourceFile);
              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
              DocumentBuilder db = dbf.newDocumentBuilder();
              Document doc = db.parse(xmlUrl.openStream());
              doc.getDocumentElement().normalize();
              //System.out.println("Root element " + doc.getDocumentElement().getNodeName());
              NodeList nodeLst = doc.getElementsByTagName("land");

              for (int s = 0; s < nodeLst.getLength(); s++)
              {
                   LandInfo li = new LandInfo();
                    Node fstNode = nodeLst.item(s);
                    if (fstNode.getNodeType() == Node.ELEMENT_NODE)
                    {
                         NodeList fstNmElmntLst = ((Element)fstNode).getElementsByTagName("naam");
                         String naam = ((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue();
                         li.setName(naam);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("id");
                         int id = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setID(id);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("r");
                         int r = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setR(r);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("g");
                         int g = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setG(g);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("b");
                         int b = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setB(b);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("x");
                         int x = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setX(x);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("y");
                         int y = Integer.parseInt(((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue());
                         li.setY(y);

                         fstNmElmntLst = ((Element)fstNode).getElementsByTagName("aangrenzend");
                         String aangrenzend = ((Node)((Element)fstNmElmntLst.item(0)).getChildNodes().item(0)).getNodeValue();

                         String[] parts = aangrenzend.split(",");
                         int[] ints = new int[parts.length];
                         for(int t = 0; t < parts.length; t++)
                         {
                             ints[t] = Integer.parseInt(parts[t]);
                         }
                    }
                    m_Landen.add(li);
              }
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
       
    }

    /**
     * Geeft een land terug op locatie (x,y), tenzij er geen land zich
     * op deze locatie bevind.
     * @param x x-coordinaat
     * @param y y-coordinaat
     * @return land op (x,y)-coordinaten
     */
    public LandInfo getLand(int x, int y)
    {
        try
        {
            // Mouse Clicked
            BufferedImage bi = ImageIO.read(ImageIO.class.getResourceAsStream(getImageUrl()));
            int rgb = bi.getRGB(x, y);

            // Bereken kleuren
            int red = (0xFF0000 & rgb) >> 16;
            int green = (0x00FF00 & rgb) >> 8;
            int blue = (0x0000FF & rgb);

            // Omdat kleuren op de kaart nooit 100% overeenkomen geven we een tolerantie aan.
            // Minimale en maximale afwijking van de opgeslagen kleur.
            int tolerance = 15;
            //int diff = 5;

            // Controleer per land of de kleur (met min. en max. afwijking 'diff')
            // overeenkomt met kleur (op locatie x,y) op het plaatje.
            List<LandInfo> foundLands = new ArrayList<LandInfo>();
            Iterator<LandInfo> it = m_Landen.iterator();
            while (it.hasNext())
            {
                LandInfo li = it.next();

                // Controleer R,G,B (met een min. en max. afwijking van 'diff':
                if (li.getR() > red - tolerance && li.getR() < red + tolerance &&     // rode waarde
                    li.getG() > green - tolerance && li.getG() < green + tolerance && // groene waarde
                    li.getB() > blue - tolerance && li.getB() < blue + tolerance)     // blauwe waarde
                {
                    // land gevonden
                    foundLands.add(li);
                }
            }

            if (foundLands.size() == 1)
                // Slechts 1 land gevonden
                return foundLands.get(0);
            else if (!foundLands.isEmpty())
            {
                // Meerdere landen gevonden
                LandInfo closestLand = null;

                // Bepaal het land dichts bij de x,y coordinaten:
                double closestDistance = Double.MAX_VALUE;
                it = foundLands.iterator();
                while (it.hasNext())
                {
                    LandInfo li = it.next();
                    // Bereken afstand tussen midden land en (x,y)-coordinaten
                    double distance = Math.sqrt(((x - li.getX()) * (x - li.getX())) + ((y - li.getY()) * (y - li.getY())));

                    // Controleer of afstand kleiner is dan kleinst gemeten afstand
                    if (distance < closestDistance)
                    {
                        // Nieuw dichtsbijzijnde land gevonden
                        closestLand = li;
                        closestDistance = distance;
                    }
                }
                return closestLand;
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
        return null;
    }

    public List<LandInfo> getLanden()
    {
        return m_Landen;
    }
    
    public LandInfo getLand(int landId)
    {
        Iterator<LandInfo> it = m_Landen.iterator();
        while (it.hasNext())
        {
            LandInfo land = it.next();
            if (land.getID() == landId)
                return land;
        }
        return null;
    }
}
